#ifndef _NET_H
#define _NET_H

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <netdb.h>
#include <stdarg.h>
#include <string.h>
#include <stdint.h>
#include <sys/time.h>
#include <signal.h>
#include <pthread.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <arpa/inet.h>
#include <netinet/if_ether.h>
#include <stdio.h>
#include <malloc.h>
#include <string.h>
#include <inttypes.h>
#include <sys/types.h>
#include <ctype.h>
#include <net/if.h>
#include <linux/if_packet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/if_ether.h>
#include <netinet/ip.h>
#include <netinet/udp.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <linux/sockios.h>

#define NO_ERR            0x0000
#define ERR_SOCKET_CREATE 0x0001
#define ERR_SOCKET_BIND   0x0002
#define ERR_SOCKET_OPT_1  0x0003
#define ERR_SOCKET_OPT_2  0x0004
#define ERR_SOCKET_OPT_3  0x0005
#define ERR_SOCKET_OPT_4  0x0006
#define ERR_SOCKET_OPT_5  0x0007
#define ERR_SOCKET_OPT_6  0x0008
#define ERR_SOCKET_OPT_7  0x0009
#define ERR_SOCKET_OPT_8  0x000A
#define ERR_SOCKET_OPT_9  0x000B
#define ERR_SOCKET_OPT_O  0x0010

#define ERR_MAIN_FLOW_INIT 0x0101
#define ERR_MAIN_FLOW_SOCK 0x0102
#define ERR_MAIN_FLOW 0x0103
#define ERR_MAIN_PRE_BUF 0x0104
////#define ERR_MAIN_FLOW 0x0105

#define ERR_SEND 0x0201
#define ERR_RECV 0x0202
#define ERR_CONNECT 0x0203

#define SOCKET_FLOW_TYPE_CLIENT 0x01
#define SOCKET_FLOW_TYPE_SERVER 0x02
#define SOCKET_TCP_TYPE_CLIENT 0x03
#define SOCKET_TCP_TYPE_SERVER 0x04

#define SOCKET_IO_TYPE_UDP_S 0x01
#define SOCKET_IO_TYPE_UDP_M 0x02
#define SOCKET_IO_TYPE_UDP_B 0x03

#define MAX_CONNECT_NUM 16
#define MAX_MESSAGE_LEN 65536

typedef uint16_t (*DFactory)(char*, uint16_t);
typedef void (*FLOW_FUNC)(void);
typedef enum _sockopt
{
	sockopt_none,
	sockopt_rcvtimeo
} sockopt;
typedef enum _socket_type
{
	socket_raw,
	socket_none

} socket_type;
typedef struct _socket_io
{
	int fd;
	socket_type s_type;
	int udp_type;
	int flow_type;
	int loopback;
	struct sockaddr_in local_addr;
	struct sockaddr_in remote_addr;
	struct ip_mreq mreq;
	struct timeval recv_timeout;
	sockopt sopt;
	struct ifreq if_req;
	char if_name[IFNAMSIZ];
	struct sockaddr_ll r_local_addr;
	struct sockaddr_ll r_remote_addr;
	void*    m_socket_data;
} socket_io,*p_socket_io;

typedef enum _flow_data_direct {
	flow_data_none,
	flow_data_back,
	flow_data_drop,
	flow_data_loop
} flow_data_direct;

typedef struct _socket_state
{
	char local_ip[16];
	char remote_ip[16];
	char mreq_ip[16];
	uint16_t local_port;
	uint16_t remote_port;
} socket_state, * p_socket_state;
typedef uint16_t (*IO_FUNC)(p_socket_io, char*, uint16_t*);

typedef struct _flow_state
{
	socket_state sstate;
	uint64_t rx_byte;
	uint64_t tx_byte;
	uint64_t rx_pkt;
	uint64_t tx_pkt;
	uint64_t err_rx_pkt;
	uint64_t err_rx_byte;
	uint64_t err_tx_pkt;
	uint64_t err_tx_byte;
	uint64_t send_limit;
	int type;
	int flow_type;
	int fd;
}flow_state, *p_flow_state;

typedef uint16_t (*InitFlow)(void*);
typedef struct _main_flow
{
	socket_io m_socket_io;
	FLOW_FUNC   m_flow_func;
	flow_data_direct     m_flow_data_direct;
	DFactory    m_fill_data;
	DFactory    m_check_data;
	IO_FUNC     m_input;
	IO_FUNC     m_output;
	flow_state  m_flow_state;
	uint8_t (*m_check_pause)(void*);
	uint8_t m_bstop;
	uint16_t m_data_size;
	uint64_t m_loop_delay;
	uint64_t m_loop_delay_max;
	InitFlow m_init_flow;
	void (*m_clean_flow)(void*);
	char plugin_parameter[256];
} main_flow, *p_main_flow;

uint16_t init_udp(p_socket_io sock);

void init_sockaddr_in(struct sockaddr_in* addr, uint32_t ip, uint16_t port, uint8_t type);

void init_sockaddr_in_2(struct sockaddr_in* addr, const char* ip, uint16_t port, uint8_t type);

void init_ip_mreq(struct ip_mreq* mreq, uint32_t loc, uint32_t mcast);

void init_ip_mreq_2(struct ip_mreq* mreq, const char* loc, const char* mcast);


void update_input_state(p_main_flow mflow, uint8_t pkt, uint16_t size, uint16_t err);
void update_output_state(p_main_flow mflow, uint8_t pkt, uint16_t size, uint16_t err);

#define DEBUG_PRINT printf("%s:%d\n", __func__, __LINE__);
#endif
